home *** CD-ROM | disk | FTP | other *** search
/ Aminet 45 / Aminet 45 (2001)(GTI - Schatztruhe)[!][Oct 2001].iso / Aminet / util / sys / JoinReplace.lha / JoinReplace / Source / Join.c next >
Encoding:
C/C++ Source or Header  |  2001-07-13  |  14.0 KB  |  554 lines

  1. #define NAME     "Join"
  2. #define REVISION "20"
  3. #define DATE     "13.07.2001"
  4.  
  5. /* Programmheader
  6.  
  7.     Name:        Join
  8.     Author:        SDI
  9.     Distribution:    PD
  10.     Description:    joins files to one big file
  11.     Compileropts:    -
  12.     Linkeropts:    -gsi
  13.  
  14.  1.4   03.10.95 : JoinToH and JoinToAG included
  15.  1.5   04.10.95 : AS as synonym for TO
  16.  1.6   15.10.95 : recompiled
  17.  1.7   15.02.95 : parameters now like in C:Join! AS=TO/K/A, FILE/M/A and
  18.     new parameter FILELIST --> Same function like before needs now AS
  19.     or TO and FILELIST!, used own startup code, new option NAMEHEADER
  20.  1.8   16.02.96 : option NAMEHEADER now also processes very long file names,
  21.     removed some other bugs
  22.  1.9   17.04.96 : added options ADD and DELSOURCE
  23.  1.10  27.04.96 : fixed error with name-printout, added option QUIET
  24.  1.11  04.05.96 : fixed error with ReadArgs
  25.  1.12  28.05.96 : now uses SDI_defines SDI_ENDCODE
  26.  1.13  12.02.97 : added option SPLITTED
  27.  1.14  18.03.97 : SDI include names changed
  28.  1.15  01.05.97 : added pattern matching, ALL and PATTERN options, made
  29.     multi-reentrant (pure bit) and removed SDI funcs this way
  30.  1.16  03.05.97 : added workbench tooltype call
  31.  1.17  04.05.97 : fixed a little bug
  32.  1.18  07.06.97 : fixed problem, when source == destination
  33.  1.19  21.08.99 : fixed PATTERN Problem
  34.  1.20  13.07.01 : fixed empty file problem
  35. */
  36.  
  37. #include <proto/dos.h>
  38. #include <proto/exec.h>
  39. #include <proto/icon.h>
  40. #include <workbench/startup.h>
  41. #include <exec/memory.h>
  42. #include "SDI_version.h"
  43. #define SDI_TO_ANSI
  44. #include "SDI_ASM_STD_protos.h"
  45.  
  46. #define PARAM    "FILE/M,AS=TO/K/A,FILELIST/K,SPLITTED/K,PAT=PATTERN/K," \
  47.         "OUTPUT/K,AG=AMIGAGUIDE/S,HEADER/S,NAMEHEADER/S,ADD/S,"    \
  48.         "DEL=DELSOURCE/S,QUIET/S,ALL/S,NOPAT=NOPATTERN/S"
  49. #define PATHNAME_SIZE    256
  50. #define NAMEHEADER_SIZE    69
  51. #define HEADERLINE_SIZE 78
  52.  
  53. #define JOINFLAG_AMIGAGUIDE    (1<<0)
  54. #define JOINFLAG_HEADER        (1<<1)
  55. #define JOINFLAG_NAMEHEADER    (1<<2)
  56. #define JOINFLAG_DELSOURCE    (1<<3)
  57. #define JOINFLAG_QUIET        (1<<4)
  58. #define JOINFLAG_NOPATTERN    (1<<5)
  59. #define JOINFLAG_ALL        (1<<6)
  60.  
  61. #define JOINERR_NOMEM        1
  62. #define JOINERR_NOFILE        2
  63. #define JOINERR_READERR        3
  64. #define JOINERR_WRITEERR    4
  65. #define JOINERR_BREAK        5
  66.  
  67. struct ExecBase *SysBase;
  68. struct DosLibrary *DOSBase;
  69. struct Library *IconBase;
  70. static const STRPTR line =
  71.   "\n/* ===================================================================== */\n\n";
  72.  
  73. struct Args
  74. {
  75.   STRPTR*files;
  76.   STRPTR to;
  77.   STRPTR filelist;
  78.   STRPTR splitted;
  79.   STRPTR pattern;
  80.   STRPTR output;
  81.   LONG     amigaguide;
  82.   LONG     header;
  83.   LONG     nameheader;
  84.   LONG     add;
  85.   LONG     delsource;
  86.   LONG     quiet;
  87.   LONG     all;
  88.   LONG     nopattern;
  89. };
  90.  
  91. static ULONG JoinMain(struct CSource *CSource);
  92. static ULONG Join(STRPTR name, ULONG filehandle, ULONG Flags);
  93. static ULONG PatJoin(STRPTR name, ULONG filehandle, ULONG Flags, STRPTR pat);
  94. static ULONG GetLength(ULONG fh);
  95.  
  96. ULONG start(void)
  97. {
  98.   struct Process *task;
  99.   struct WBStartup *msg = 0;
  100.   ULONG ret = RETURN_FAIL;
  101.   struct DosLibrary *dosbase;
  102.   struct CSource csr;
  103.  
  104.   SysBase = (*((struct ExecBase **) 4));
  105.   /* test for WB and reply startup-message */
  106.   if(!(task = (struct Process *) FindTask(0))->pr_CLI)
  107.   {
  108.     WaitPort(&task->pr_MsgPort);
  109.     msg = (struct WBStartup *) GetMsg(&task->pr_MsgPort);
  110.   }
  111.  
  112.   memset(&csr, 0, sizeof(struct CSource));
  113.   if((dosbase = (struct DosLibrary *) OpenLibrary("dos.library", 37)))
  114.   {
  115.     DOSBase = dosbase;
  116.     
  117.     if(!msg) /* CLI call - only one argument string */
  118.       ret = JoinMain(&csr);
  119.     else
  120.     {
  121.       struct Library *iconbase;
  122.  
  123.       if((iconbase = OpenLibrary("icon.library", 37)))
  124.       {
  125.         ULONG i;
  126.         IconBase = iconbase;
  127.  
  128.     ret = RETURN_OK;
  129.         for(i = 0; !ret && i < msg->sm_NumArgs; ++i)
  130.         {
  131.       ULONG lock;
  132.       struct DiskObject *dobj;
  133.  
  134.           lock = CurrentDir(msg->sm_ArgList[i].wa_Lock);
  135.           if((dobj = GetDiskObject(msg->sm_ArgList[i].wa_Name)))
  136.           {
  137.             if(dobj->do_ToolTypes)
  138.             {
  139.               char **str = dobj->do_ToolTypes;
  140.  
  141.               while(!ret && *str)
  142.               {
  143.                   STRPTR buf;
  144.          csr.CS_Length = strlen(*str)+1; /* add \n */
  145.          if((buf = (STRPTR) AllocMem(csr.CS_Length+1, MEMF_ANY)))
  146.          {
  147.            CopyMem(*str, buf, csr.CS_Length);
  148.            buf[csr.CS_Length] = 0;
  149.            buf[csr.CS_Length-1] = '\n';
  150.           csr.CS_Buffer = buf;
  151.           ret = JoinMain(&csr);
  152.           FreeMem(buf, csr.CS_Length+1);
  153.         }
  154.         else
  155.           ret = RETURN_FAIL;
  156.                 ++str;
  157.               }
  158.             }
  159.             FreeDiskObject(dobj);
  160.           }
  161.           CurrentDir(lock);
  162.         }
  163.         CloseLibrary(iconbase);
  164.       }
  165.     }
  166.     CloseLibrary((struct Library *) dosbase);
  167.   }
  168.  
  169.   if(msg)
  170.   {
  171.     Forbid();
  172.     ReplyMsg((struct Message *) msg);
  173.   }
  174.  
  175.   return ret;
  176. }
  177.  
  178. static ULONG JoinMain(struct CSource *CSource)
  179. {
  180.   struct Args args;
  181.   LONG i = 0;
  182.   ULONG Flags = 0, ret = RETURN_FAIL, dest, patbufsize = 0, out = 0, oldout = 0;
  183.   STRPTR pattern = 0;
  184.   struct RDArgs *rda;
  185.  
  186.   memset(&args, 0, sizeof(struct Args));
  187.   if((rda = (struct RDArgs *) AllocDosObject(DOS_RDARGS, 0)))
  188.   {
  189.    rda->RDA_ExtHelp =
  190.    "FILES      files, which should be joined\n"
  191.    "FILELIST   takes the filenames out of a file (every line contains\n"
  192.    "           a complete filename)\n"
  193.    "SPLITTED   allows joining splitted files, data has to look like:\n"
  194.    "           <filename>[,<first number>[,<last number>]], filename has\n"
  195.    "           to hold ONE format string like %ld,%03ld,%lx,%2lx,\n"
  196.    "           numbers have to be decimal\n\n"
  197.    "PATTERN    gives pattern filename must match\n"
  198.    "OUTPUT     specifies output path\n\n"
  199.    "AMIGAGUIDE at the start of every file @node \"filename\" and at the\n"
  200.    "           end @endnode is inserted\n"
  201.    "HEADER     /* ======== ... ========= */ is inserted at filestart\n"
  202.    "NAMEHEADER /* ===... filename ...=== */ is inserted at filestart\n"
  203.    "ADD        adds the files to an existing destination file\n"
  204.    "DELSOURCE  deletes the sourcefiles\n"
  205.    "QUIET      brings no output\n"
  206.    "ALL        scan into directories\n"
  207.    "NOPATTERN  take names as given";
  208.  
  209.    rda->RDA_Source.CS_Buffer = CSource->CS_Buffer;
  210.    rda->RDA_Source.CS_Length = CSource->CS_Length;
  211.  
  212.    if(ReadArgs(PARAM, (LONG *) &args, rda))
  213.    {
  214.     if(args.amigaguide)    Flags |= JOINFLAG_AMIGAGUIDE;
  215.     if(args.header)    Flags |= JOINFLAG_HEADER;
  216.     if(args.nameheader)    Flags |= JOINFLAG_NAMEHEADER;
  217.     if(args.delsource)    Flags |= JOINFLAG_DELSOURCE;
  218.     if(args.quiet)    Flags |= JOINFLAG_QUIET;
  219.     if(args.nopattern)    Flags |= JOINFLAG_NOPATTERN;
  220.     if(args.all)    Flags |= JOINFLAG_ALL;
  221.  
  222.     if(args.output && (out = Open(args.output, MODE_NEWFILE)))
  223.       oldout = SelectOutput(out);
  224.  
  225.     if(args.files)    ++i;
  226.     if(args.filelist)    ++i;    /* test if only one of these three */
  227.     if(args.splitted)    ++i;
  228.     if(i == 1 && (dest = Open(args.to, MODE_READWRITE)))
  229.     {
  230.      if(args.add)
  231.       Seek(dest, 0, OFFSET_END);
  232.      else
  233.       SetFileSize(dest, 0, OFFSET_BEGINNING); /* cut when already exists */
  234.  
  235.      if(args.pattern && *args.pattern)
  236.      {
  237.       patbufsize = (strlen(args.pattern)<<1) + 1;
  238.       if((pattern = (STRPTR) AllocMem(patbufsize, MEMF_PUBLIC)))
  239.       {
  240.        if(ParsePatternNoCase(args.pattern, pattern, patbufsize) < 0)
  241.        {
  242.     FreeMem(pattern, patbufsize); pattern = 0;
  243.        }
  244.       }
  245.      }
  246.  
  247.      if(args.pattern && !pattern)
  248.      {
  249.       if(!*args.pattern)
  250.        SetIoErr(ERROR_BAD_TEMPLATE);
  251.      }
  252.      else if(args.splitted)
  253.      {
  254.       UBYTE name[PATHNAME_SIZE];
  255.       STRPTR a, b, *e = 0, *f = 0;
  256.       LONG spl_start = 0, spl_end = 0;
  257.  
  258.       ret = RETURN_OK;
  259.       for(a = args.splitted; *a && *a != ','; ++a)
  260.        ;
  261.       if(*a == ',')
  262.       {
  263.        *(a++) = 0;
  264.        for(b = a; *b && *b != ','; ++b)
  265.         ;
  266.       
  267.        if(*b == ',')
  268.        {
  269.         *(b++) = 0;
  270.         spl_end = strtol(b,f,10);
  271.        }
  272.        spl_start = strtol(a,e,10);
  273.  
  274.        if(e || f || (spl_end && spl_end < spl_start))
  275.        {
  276.         SetIoErr(ERROR_BAD_NUMBER);
  277.         ret = RETURN_FAIL;
  278.        }
  279.       }
  280.  
  281.       while(!ret && (!spl_end || spl_end >= spl_start))
  282.       {
  283.        sprintf(name, args.splitted, spl_start++);
  284.        if((i = PatJoin(name, dest, Flags, pattern)))
  285.        {
  286.         if(i != JOINERR_NOFILE)
  287.          ret = RETURN_FAIL;
  288.         else if(!spl_end)
  289.          break;
  290.        }
  291.       }
  292.      }
  293.      else if(args.filelist)
  294.      {
  295.       ULONG fh, bufsize;
  296.       STRPTR buffer, pos, name;
  297.  
  298.       if((fh = Open(args.filelist, MODE_OLDFILE)))
  299.       {
  300.        bufsize = GetLength(fh);
  301.        if((pos = buffer = (STRPTR) AllocMem(bufsize+1, MEMF_ANY)))
  302.        {
  303.         if(Read(fh, buffer, bufsize) == bufsize)
  304.     {
  305.          ret = RETURN_OK;
  306.          while(pos < buffer + bufsize)
  307.          {
  308.           name = pos;
  309.           while(pos < buffer + bufsize && *pos != '\n')
  310.        ++pos;
  311.       *(pos++) = 0;
  312.           if(PatJoin(name, dest, Flags, pattern))
  313.            ret = RETURN_FAIL;
  314.          }
  315.         }
  316.         FreeMem(buffer, bufsize+1);
  317.        }
  318.        Close(fh);
  319.       }
  320.      }
  321.      else
  322.      {
  323.       ret = RETURN_OK;
  324.       while(*args.files)
  325.       {
  326.        if(PatJoin(*(args.files++), dest, Flags, pattern))
  327.        {
  328.          ret = RETURN_FAIL; break;
  329.        }
  330.       }
  331.      }
  332.      if(pattern)
  333.       FreeMem(pattern, patbufsize);
  334.      Close(dest);
  335.     } /* Open dest */
  336.     else if(!i)
  337.      SetIoErr(ERROR_REQUIRED_ARG_MISSING);
  338.     else if(i != 1)
  339.      SetIoErr(ERROR_TOO_MANY_ARGS);
  340.  
  341.     FreeArgs(rda);
  342.    } /* ReadArgs */
  343.    FreeDosObject(DOS_RDARGS, rda);
  344.   }
  345.  
  346.   if(!ret && (SetSignal(0L,0L) & SIGBREAKF_CTRL_C))
  347.   {
  348.     SetIoErr(ERROR_BREAK);
  349.     ret = RETURN_WARN;
  350.   }
  351.  
  352.   if(ret && !args.quiet)
  353.     PrintFault(IoErr(),0);
  354.  
  355.   if(out)
  356.     Close(SelectOutput(oldout));
  357.  
  358.   return ret;
  359. }
  360.  
  361. /* every list entry of filelist is a memory block which contains pointer
  362.    to next block and behind this the filename string */
  363.  
  364. static ULONG PatJoin(STRPTR name, ULONG dest, ULONG Flags, STRPTR pattern)
  365. {
  366.   if(Flags & JOINFLAG_NOPATTERN)
  367.     return Join(name, dest, Flags);
  368.   else
  369.   {
  370.    struct AnchorPath *APath;
  371.    ULONG *filelist = 0, *a, *b, retval;
  372.    ULONG ret = JOINERR_NOMEM;
  373.    LONG i;
  374.  
  375.    if((APath = (struct AnchorPath *) AllocMem(sizeof(struct AnchorPath)+
  376.    PATHNAME_SIZE, MEMF_PUBLIC|MEMF_CLEAR)))
  377.    {
  378.     APath->ap_BreakBits = SIGBREAKF_CTRL_C;
  379.     APath->ap_Strlen = PATHNAME_SIZE;
  380.  
  381.     for(retval = MatchFirst(name, APath); !retval; retval =MatchNext(APath))
  382.     {
  383.      if(APath->ap_Flags & APF_DIDDIR)
  384.        APath->ap_Flags &= ~APF_DIDDIR;
  385.      else if(APath->ap_Info.fib_DirEntryType > 0)
  386.      {
  387.       if(Flags & JOINFLAG_ALL)
  388.        APath->ap_Flags |= APF_DODIR;
  389.      }
  390.      else if(!pattern || MatchPatternNoCase(pattern, APath->ap_Buf))
  391.      {
  392.       i = strlen(APath->ap_Buf)+1;
  393.       if(!(a = (ULONG *) AllocVec(i+4, MEMF_ANY)))
  394.        break;
  395.       CopyMem(APath->ap_Buf, a+1, i);
  396.       if(!filelist)
  397.       {
  398.        filelist = a; *a = 0;
  399.       }
  400.       else if(stricmp((STRPTR) (filelist+1), APath->ap_Buf) >= 0)
  401.       {
  402.        *a = (ULONG) filelist; filelist = a;
  403.       }
  404.       else
  405.       {
  406.        for(b = filelist; *b && (i = stricmp((STRPTR) (*b+4),
  407.        APath->ap_Buf)) < 0; b = (ULONG *) *b)
  408.         ;
  409.        *a = *b; *b = (ULONG) a;
  410.       }
  411.      }
  412.     }
  413.     MatchEnd(APath);
  414.  
  415.     if(retval == ERROR_NO_MORE_ENTRIES)
  416.     {
  417.      for(a = filelist; a; a = (ULONG *) *a)
  418.      {
  419.       if((ret = Join((STRPTR) (a+1), dest, Flags)))
  420.        break;
  421.      }
  422.     }
  423.  
  424.     while(filelist)
  425.     {
  426.      a = (ULONG *) *filelist;
  427.      FreeVec(filelist);
  428.      filelist = a;
  429.     }
  430.     FreeMem(APath, sizeof(struct AnchorPath)+PATHNAME_SIZE);
  431.    }
  432.    return ret;
  433.   }
  434. }
  435.  
  436. static ULONG Join(STRPTR name, ULONG dest, ULONG Flags)
  437. {
  438.   ULONG file, lock_old, lock_new, bufsize, ret = 0;
  439.   LONG i;
  440.   UBYTE namebuffer[NAMEHEADER_SIZE+1];
  441.   ULONG namel;
  442.   STRPTR buffer;
  443.  
  444.   if((lock_new = Lock(name, SHARED_LOCK)))
  445.   {
  446.     if((lock_old = DupLockFromFH(dest)))
  447.     {
  448.       if(SameLock(lock_new, lock_old) == LOCK_SAME)
  449.       {
  450.         if(!(Flags & JOINFLAG_QUIET))
  451.           PutStr("Destination file skipped.\n");
  452.         UnLock(lock_new); lock_new = 0;
  453.       }
  454.       UnLock(lock_old);
  455.     }
  456.   }
  457.   else
  458.     ret = JOINERR_NOFILE;
  459.  
  460.   if(!lock_new)
  461.     return ret;
  462.  
  463.   if((file = OpenFromLock(lock_new)))
  464.   {
  465.     bufsize = GetLength(file);
  466.     if((i = AvailMem(MEMF_LARGEST)) < bufsize)
  467.       bufsize = i;
  468.     if(!bufsize)
  469.       bufsize = 1; /* prevent allocmem failure */
  470.     if((buffer = (STRPTR) AllocMem(bufsize, MEMF_ANY)))
  471.     {
  472.       if(Flags & JOINFLAG_AMIGAGUIDE)
  473.       {
  474.         Write(dest, "@node \"", 7);
  475.     Write(dest, name, i);
  476.     Write(dest, "\"\n", 2);
  477.       }
  478.       if(Flags & JOINFLAG_HEADER && Seek(dest, 0, OFFSET_CURRENT))
  479.         Write(dest, line, HEADERLINE_SIZE);
  480.       namel = strlen(name);
  481.       if(namel > NAMEHEADER_SIZE)
  482.       {
  483.         namebuffer[0] = namebuffer[1] = namebuffer[2] = '.';
  484.         CopyMem(name+namel-(NAMEHEADER_SIZE-3), namebuffer+3, NAMEHEADER_SIZE-3+1);
  485.         namel = NAMEHEADER_SIZE;
  486.       }
  487.       else
  488.         CopyMem(name, namebuffer, namel+1);
  489.       if(Flags & JOINFLAG_NAMEHEADER)
  490.       {
  491.         i = (NAMEHEADER_SIZE-namel)>>1;
  492.         Write(dest, line, 3+i);
  493.     Write(dest, " ", 1);
  494.         Write(dest, namebuffer, namel);
  495.         Write(dest, " ", 1);
  496.     i += 5+namel;
  497.         Write(dest, line+i, HEADERLINE_SIZE-i);
  498.       }
  499.       while((i = Read(file, buffer, bufsize)) > 0)
  500.       {
  501.         if(Write(dest, buffer, i) == -1)
  502.         {
  503.           ret = JOINERR_WRITEERR; break;
  504.         }
  505.       }
  506.       if(i == -1)
  507.         ret = JOINERR_READERR;
  508.  
  509.       if(!ret && (Flags & JOINFLAG_AMIGAGUIDE))
  510.         Write(dest, "\n@endnode\n\n", 11);
  511.  
  512.       FreeMem(buffer, bufsize);
  513.     }
  514.     else
  515.       ret = JOINERR_NOMEM;
  516.     Close(file);
  517.   }
  518.   else
  519.   {
  520.     UnLock(lock_new);
  521.     ret = JOINERR_NOFILE;
  522.   }
  523.  
  524.   if(!ret)
  525.   {
  526.     if(Flags & JOINFLAG_DELSOURCE)
  527.       DeleteFile(name);
  528.     if(!(Flags & JOINFLAG_QUIET))
  529.     {
  530.       PutStr(namebuffer); PutStr(" joined");
  531.       if(Flags & JOINFLAG_DELSOURCE)
  532.         PutStr(" and deleted");
  533.       PutStr(".\n");
  534.     }
  535.     if(SetSignal(0L,0L) & SIGBREAKF_CTRL_C)
  536.       ret = JOINERR_BREAK;
  537.   }
  538.   return ret;
  539. }
  540.  
  541. static ULONG GetLength(ULONG fh)
  542. {
  543.   struct FileInfoBlock *fib;
  544.   ULONG ret = 0xFFFFFFFF;
  545.  
  546.   if((fib = (struct FileInfoBlock *) AllocDosObject(DOS_FIB, 0)))
  547.   {
  548.    if(ExamineFH(fh, fib))
  549.     ret = fib->fib_Size;
  550.    FreeDosObject(DOS_FIB,fib);
  551.   }
  552.   return ret;
  553. }
  554.